package oss

import (
    "bytes"
    "context"
    "fmt"
    "strings"

    "github.com/h2non/filetype"
    "github.com/minio/minio-go/v7"
    "github.com/minio/minio-go/v7/pkg/credentials"
    uuid "github.com/satori/go.uuid"
    "go.uber.org/zap"
)

type Minio struct {
    cfg    *Config
    l      *zap.Logger
    logger *zap.SugaredLogger
}

type MinioBucket struct {
    logger *zap.SugaredLogger
    client *minio.Client
    bucket string
    cfg    *Config
}

func NewMinio() *Minio {
    x := &Minio{}
    return x
}

func (s *Minio) WithLogger(l *zap.Logger) *Minio {
    s.l = l.With(zap.String("mod", "account"))
    s.logger = s.l.Sugar()
    return s
}

func (s *Minio) WithConfig(c *Config) *Minio {
    s.cfg = c
    return s
}

func (s *Minio) OpenBucket(bucket string) (*MinioBucket, error) {
    x := &MinioBucket{}
    x.logger = s.logger
    x.cfg = s.cfg
    x.bucket = strings.ToLower(bucket)

    minioClient, err := minio.New(s.cfg.Endpoint, &minio.Options{
        Creds:  credentials.NewStaticV4(s.cfg.AccessKey, s.cfg.Secretkey, ""),
        Secure: false,
    })
    if err != nil {
        s.logger.Error(err)
        return nil, err
    }

    x.client = minioClient

    exists, err := minioClient.BucketExists(context.Background(), bucket)
    if err != nil {
        s.logger.Error(err)
        return nil, err
    }
    if exists {
        goto _exist
    }

    err = minioClient.MakeBucket(context.Background(), bucket, minio.MakeBucketOptions{Region: `us-east-1`})
    if err != nil {
        s.logger.Error(err)
        return nil, err
    }
    s.logger.Info("oss create bucket done")
_exist:
    return x, nil
}

func (s *MinioBucket) Store(ctx context.Context, b []byte) (string, error) {
    kind, err := filetype.Match(b)
    if err != nil {
        return "", err
    }
    if kind == filetype.Unknown {
        return "", fmt.Errorf("Unknown file type")
    }

    name := uuid.NewV4().String() + "." + kind.Extension
    info, err := s.client.PutObject(ctx, s.bucket, name, bytes.NewReader(b), int64(len(b)), minio.PutObjectOptions{
        ContentType: kind.MIME.Value,
    })
    if err != nil {
        return "", err
    }
    _ = info
    return name, nil
}
